﻿#include "PTMemorySystemImpl.h"
#include <new>
#include <assert.h>

static PTMemorySystemImpl g_Singleton;

extern "C" PTSYSTEMAPI IPTMemorySystem * PTCALL PTMemorySysem_Get()
{
	return &g_Singleton;
}

IPTHeap * PTCALL PTMemorySystemImpl::HeapCreate(size_t MaxSize)
{
	//向上取整到2的幂次方
	if (MaxSize&(MaxSize - 1U))
	{
		size_t MaxSizeIndex = 0U;
		MaxSize -= 1U;
		while (MaxSize)
		{
			++MaxSizeIndex;
			MaxSize >>= static_cast<size_t>(1U);
		}
		MaxSize = static_cast<size_t>(1U) << MaxSizeIndex;
	}

	LARGE_INTEGER liHeapImplSize;
	liHeapImplSize.QuadPart = static_cast<LONGLONG>(sizeof(PTHeapImpl) + PTAllocatorBuddy::GetAdditionalSizeRequire(MaxSize, 32U));
	HANDLE hSectionHeapImpl = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, liHeapImplSize.HighPart, liHeapImplSize.LowPart, NULL);
	void *pMemoryHeapImpl = ::MapViewOfFile(hSectionHeapImpl, FILE_MAP_READ | FILE_MAP_WRITE, 0U, 0U, 0U);

	LARGE_INTEGER liBlockWholeSize;
	liBlockWholeSize.QuadPart = static_cast<LONGLONG>(MaxSize);
	HANDLE hSectionBlockWhole = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, liBlockWholeSize.HighPart, liBlockWholeSize.LowPart, NULL);
	void *pMemoryBlockWhole = ::MapViewOfFile(hSectionBlockWhole, FILE_MAP_READ | FILE_MAP_WRITE, 0U, 0U, 0U);

	//由于PTBlockBusyHeader的开销，实际可用的数据会小于BlockWholeSize

	IPTHeap *pHeap = ::new(pMemoryHeapImpl)PTHeapImpl(hSectionHeapImpl, pMemoryHeapImpl, hSectionBlockWhole, pMemoryBlockWhole, MaxSize, 32U);
	return pHeap;	 
}

PTHeapImpl::PTHeapImpl(HANDLE hSectionHeapImpl, void *pMemoryHeapImpl, HANDLE hSectionBlockWhole, void *pMemoryBlockWhole, size_t BlockWholeSize, size_t BlockMinimumSize) :m_hSectionHeapImpl(hSectionHeapImpl), m_pMemoryHeapImpl(pMemoryHeapImpl), m_hSectionBlockWhole(hSectionBlockWhole), m_pMemoryBlockWhole(pMemoryBlockWhole), m_pAllocatorBuddy(BlockWholeSize, BlockMinimumSize, pMemoryBlockWhole)
{

}

PTHeapImpl::~PTHeapImpl()
{
	::UnmapViewOfFile(this->m_pMemoryBlockWhole);

	HANDLE hSectionHeapImpl = this->m_hSectionHeapImpl;
	HANDLE hSectionBlockWhole = this->m_hSectionBlockWhole;

	::UnmapViewOfFile(this->m_pMemoryHeapImpl);//m_hSectionXXX在UnmapViewOfFile后失效

	::CloseHandle(hSectionHeapImpl);
	::CloseHandle(hSectionBlockWhole);
}

void PTCALL PTHeapImpl::Destroy()
{
	this->~PTHeapImpl();
}

void * PTCALL PTHeapImpl::AlignedAlloc(size_t Size, size_t Alignment)
{
	return m_pAllocatorBuddy.AlignedAlloc(Size, Alignment);
}

void * PTCALL PTHeapImpl::AlignedRealloc(void *pBlock, size_t Size, size_t Alignment)
{
	if (pBlock == NULL)
	{
		return m_pAllocatorBuddy.AlignedAlloc(Size, Alignment);
	}
	else if (Size == 0U)
	{
		m_pAllocatorBuddy.AlignedFree(pBlock);
		return NULL;
	}
	else
	{
		return m_pAllocatorBuddy.AlignedRealloc(pBlock, Size, Alignment);
	}
}

void PTCALL PTHeapImpl::AlignedFree(void* pBlock)
{
	if (pBlock != NULL)
	{
		m_pAllocatorBuddy.AlignedFree(pBlock);
	}
}